<?php

class Myzen_Oauth_Consumer {

	public $key;
	public $secret;
	public $name;
	protected $_callbackURL;
	protected $_userId;
	
	/* defintion of the consumer table */
	static protected $_dbConsumerTableName = 'consumers';
	static protected $_dbConsumerKeyCol = 'key';
	static protected $_dbConsumerDataCol = 'data';
	
	
	static protected $_dbConsumerDataAppNameElem = 'appName';  
	static protected $_dbConsumerDataSecretElem = 'secret'; 
	static protected $_dbConsumerDataUserIdElem = 'UserId';
	static protected $_dbConsumerDataCallbackURLElem = 'callbackURL';


	/* defintion of the user Index */
	static protected $_dbConsumerUserIndexTableName = 'userIndex';
	static protected $_dbConsumerUserIndexKeyCol = 'key';
	static protected $_dbConsumerUserIndexUserIdCol = 'userId';

	
	public function __construct($key,$data = '') {
	
		if(!empty($key)) {
			$db = Zend_Registry::get('dt_dbs')->getDb('auth','consumer','key');
			$select = $db->select()->from(self::$_dbConsumerTableName);
			$where = $db->quoteInto(self::$_dbConsumerKeyCol ." = ?", $key);
			$select->where($where);
			$res = $db->fetchAll($select->__toString()); 
			
			if(empty($res)) throw new Myzen_Oauth_Exception('Consumer not found',5);
			$data = $res[0];
		}    
		
		$this->key = $data[self::$_dbConsumerKeyCol];

		//the data is encoded in gz base64 for storage purpose
		$blobDetails = self::decode($data[self::$_dbConsumerDataCol]);
		
		$this->secret = $blobDetails[self::$_dbConsumerDataSecretElem];
		$this->name = $blobDetails[self::$_dbConsumerDataAppNameElem];
		$this->_callbackURL = $blobDetails[self::$_dbConsumerDataCallbackURLElem];
		$this->_userId = $blobDetails[self::$_dbConsumerDataUserIdElem];
	
	}
	
	public function getCallbackURL() {
		return $this->_callbackURL;
	}


	public function getKey() {
		return $this->key;
	}	

	public function getAppName() {
		return $this->name;
	}	

	public function getUserId() {
		return $this->_userId;
	}
	
	public function getSecret() {
		return $this->secret;
	}

	
	public function asArray($detailsLevel = 'low') {
		$data = array();
		$data['key'] = $this->getKey();
		$data['applicationName'] = $this->getAppName();
		$data['userId'] = $this->getUserId();
		if($detailsLevel == 'medium' || $detailsLevel == 'high') {
			$data['nbAuthenticatedUsers'] = $this->_getNbAuthenticatedUsers();			
		}
		if($detailsLevel == 'high') {
			$data['secret'] = $this->getSecret();				
			$data['callbackURL'] = $this->getCallbackURL();
		}
		return $data;		
	}
	
	
	//this function returns the different keys that belong to a user given by user id
	//keys are Myzen_Oauth_Consumer objects stored in an array
	static protected function _getKeysByUserId($userId) {
			$db = Zend_Registry::get('dt_dbs')->getDb('auth','consumer','key');
			$select = $db->select()->from(self::$_dbConsumerUserIndexTableName,self::$_dbConsumerUserIndexKeyCol);
			
			$where = $db->quoteInto(self::$_dbConsumerUserIndexUserIdCol ." = ?", $userId);
			$select->where($where);
			$res = $db->fetchAll($select->__toString());
			
			if(empty($res)) return array();	
			
			$KeysNameList = array();
			foreach($res as $num => $details) $KeysNameList[] = $details[self::$_dbConsumerUserIndexKeyCol];
			
			$select = $db->select()->from(self::$_dbConsumerTableName);
			$select->where(self::$_dbConsumerKeyCol ." IN (?)", $KeysNameList);
			$resKeys = $db->fetchAll($select->__toString());			
			
			if(empty($resKeys)) return array();
			$keys = array();
			foreach($resKeys as $num => $keyDetails) {
				$keys[] = new Myzen_Oauth_Consumer('',$keyDetails);
			}
			
			return $keys;
			
	}
	
	
	protected function _getNbAuthenticatedUsers() {
		require_once('Myzen/Oauth/Token/Access.php');
		return Myzen_Oauth_Token_Access::getNbAuthenticatedUserByConsumer($this->getKey());
	}
	
	public static function getAuthenticatedUserKeys() {
	  	//we need to get the email of the user
		$userId = (int) Zend_Registry::get('app_user')->getId();
		return self::_getKeysByUserId($userId,'high');
	}
	
	
	public function __toString() {
		return "OAuthConsumer[key=$this->key]";
	}
	
	

	//add a key to the list of keys
	//if ok, returns a Myzen_Oauth_Consumer object
	static public function add($params) {

		//we create a new key using some randomness available in config
		$blowfish = Zend_Registry::get('dt_config')->blowfish;
		
		//We create a new secret
		//secret is 40 alphanum
		$secret = sha1(time().md5($blowfish).rand());

		if(empty($params['userId'])) {
			$userId =  (int) Zend_Registry::get('app_user')->getId();
		} else {
			//We check that the user exists
			require_once('Myzen/User.php');
			$user = new Myzen_User(array('id' => $params['userId']));
			$userId = $user->getId();
		}
		
		//We check that the security is in place for the user to create a key (to do)
		//and the other user to be associated a key
		
		//We check that if filled the callbackURL is valid
		$validator = new Zend_Validate_Callback(array('Zend_Uri', 'check'));
		if (!$validator->isValid($params['callbackURL'])) {
			throw new Myzen_Oauth_Exception('callbackURL is empty or not valid',7);
		}
		$callbackURL = $params['callbackURL'];
		
		//we check that the appname is devoid of any html
		require_once('htmlpurifier/library/HTMLPurifier.auto.php');
		$config = HTMLPurifier_Config::createDefault();
		$config->set('HTML.Allowed', '');
		$purifier = new HTMLPurifier($config);
		$appName = $purifier->purify(trim($params['appName']));		
		
		if(empty($appName))  throw new Myzen_Oauth_Exception('AppName is empty or not valid',6);
		
		//OK we seems to have everything to create the new key
		$data = array(
			self::$_dbConsumerDataAppNameElem => $appName,
			self::$_dbConsumerDataSecretElem => $secret,
			self::$_dbConsumerDataUserIdElem => $userId,
			self::$_dbConsumerDataCallbackURLElem => $callbackURL  		
		);
		
		//we are not sure the key is not already assigned so we loop until we find a key that is not already given
		//we put a limit to avoid infinite loop
		$limit = 0;
		$db = Zend_Registry::get('dt_dbs')->getDb('auth','consumer','key');	
		
		$tobeInserted = array(
			self::$_dbConsumerKeyCol => '',
			self::$_dbConsumerDataCol => self::encode($data)
		);
		
		while(true) {
			$limit++;
			if($limit >= 10)  throw new Myzen_Oauth_Exception('Issue will creating new consumer: limit reached',25);
			
			//key is 8 alphanum
			$key = substr(sha1(rand().time().$blowfish),rand(1,20),8);
	
			//we update the key in the data to insert in db
			$tobeInserted[self::$_dbConsumerKeyCol] = $key;
			//we try inserting the data
			$db->insert(self::$_dbConsumerTableName, $tobeInserted);			
			
			break;
		}
		//We create the indexes
		//User index
		$userIndexData = array(
			self::$_dbConsumerUserIndexKeyCol => $key,
			self::$_dbConsumerUserIndexUserIdCol => $userId
		);

		$db->insert(self::$_dbConsumerUserIndexTableName, $userIndexData);

		
		//We return the key
		return new Myzen_Oauth_Consumer($key);
		//echo self::encode($data);
	}//end add

  
  
	//the message is stored as a base64 gzdefalted serialized PHP
	static public function decode($data) {
		$decoded = unserialize(gzinflate(base64_decode($data)));
		if(empty($decoded)) {
			require_once('status/objects/Exception.php');
			throw new Myzen_Oauth_Exception('An issue occured while decoding message',16);
		}  
		return  $decoded;	
	} //end decode
	
	static public function encode($data) {
		if(!is_array($data)) {
			throw new Myzen_Oauth_Exception('input parameter is not an array',12); 
		}
		$encoded = @base64_encode(gzdeflate(serialize($data),9));
		if(empty($encoded)) {
			throw new Myzen_Oauth_Exception('An issue occured while encoding message',17);
		} 
		return $encoded;   	
	} //end encode
  
  
}